
#ifdef VARIANT_SERIALIZATION
    #include <boost/serialization/vector.hpp>
    #include <boost/serialization/string.hpp>
    #include <boost/serialization/list.hpp>
    #include <boost/serialization/map.hpp>
#endif

namespace tools{

//---------------------------------------------------------------------------------------------
    #define ONLY_WSTREAM \
        typename ::std::enable_if< ::std::is_same<wchar_t, T>::value, T >::type*
    #define ONLY_STREAM \
    typename ::std::enable_if< ::std::is_same<char, T>::value, T >::type*

    template<class T>void ToStream(::std::basic_ostream<T>& os, const Variant& obj, ONLY_WSTREAM)
    {
        typedef variant_detail::V::WStr  WStr;
        typedef variant_detail::V::WChar WChar;

        if(obj.Is<WStr>())
            variant_detail::Out<WStr>::ToString( obj.mData.Resource<void>(), os );
        else if(obj.Is<WChar>())
            variant_detail::Out<WChar>::ToString( obj.mData.Resource<void>(), os );
        else
            os<< obj.ToString().c_str();
    }
    template<class T>void ToStream(::std::basic_ostream<T>& os, const Variant& obj, ONLY_STREAM)
    {
        os<< obj.ToString().c_str();
    }
    #undef ONLY_WSTREAM
    #undef ONLY_STREAM

//---------------------------------------------------------------------------------------------

    template<class T> bool Variant::operator == (const T& rhs)const
    {
        static_assert( !variant_detail::PropertyType<T>::eIS_BANNED, "THIS TYPE NOT SUPPORT" );
        typedef typename variant_detail::PropertyType<T>::Type Type;
        enum { eMYTYPE = variant_detail::Type2Enum<Type>::eTYPE };

        if(Empty())
            return false;

        return mHelper->Compare(mData.Resource(), &rhs, static_cast<variant_detail::eTYPE>(eMYTYPE) );
    }
    template<class T> bool Variant::operator != (const T& rhs)const
    {
        return !operator==(rhs);
    }
//---------------------------------------------------------------------------------------------
    template<class T> Variant& Variant::operator= (const T& src)
    {
        static_assert( !variant_detail::PropertyType<T>::eIS_BANNED, "THIS TYPE NOT SUPPORT" );
        mHelper = variant_detail::Helper<T>();
        mData   = src;
        return *this;
    }
//---------------------------------------------------------------------------------------------
    template<class T> bool Variant::Is()const
    {
        static_assert( !variant_detail::PropertyType<T>::eIS_BANNED, "THIS TYPE NOT SUPPORT" );

        typedef typename variant_detail::PropertyType<T>::Type Type;
        const eTYPE type = static_cast<eTYPE>(variant_detail::Type2Enum<Type>::eTYPE);
        return Empty()? false: mHelper->IsTypeSame(type);
    }
//---------------------------------------------------------------------------------------------
    template<class T> Variant::operator const T&()const
    {
        static_assert( !variant_detail::PropertyType<T>::eIS_BANNED, "THIS TYPE NOT SUPPORT" );

        if(Empty() )
            throw ::std::runtime_error("ERROR_EMPTY_VARIANT"); 

        ThrowIfFalse( Is<T>() );
        const T& data = *mData.Resource<T>();
        return data;
    }
    template<class T> Variant::operator T&() 
    {
        const T& ref = const_cast<const Variant&>(*this);
        return const_cast<T&>(ref);  
    }
//---------------------------------------------------------------------------------------------
    template<class T> bool Variant::Can()const
    {
        if(Empty())
            return false;

        typedef variant_detail::PropertyType<T> Property;
        if(Property::eIS_STRICT)
            return Is<T>();
        if(sizeof(T) < SizeData())
            return false;
        if(Property::eIS_INT)
            return IsInteger();
        if(Property::eIS_FLOAT)
            return IsFloating() || IsInteger();
        return false;
    }
//---------------------------------------------------------------------------------------------
    template<class T> T Variant::CastType()const
    {
        using namespace variant_detail;

        if(Empty() )
            throw ::std::runtime_error("ERROR_INVALID_CAST_INTEGRAL_TYPE_EMPTY_VARIANT"); 

        const eTYPE type = mHelper->GetType();

        switch (type)
        {
            case eI8:   return static_cast<T>(mData.Cast<I8>() );
            case eI16:  return static_cast<T>(mData.Cast<I16>());
            case eI32:  return static_cast<T>(mData.Cast<I32>());
            case eI64:  return static_cast<T>(mData.Cast<I64>());
            case eU8:   return static_cast<T>(mData.Cast<U8>() );
            case eU16:  return static_cast<T>(mData.Cast<U16>());
            case eU32:  return static_cast<T>(mData.Cast<U32>());
            case eU64:  return static_cast<T>(mData.Cast<U64>());
            case eF32:  return static_cast<T>(mData.Cast<F32>());
            case eF64:  return static_cast<T>(mData.Cast<F64>());
        default:
            throw ::std::runtime_error("ERROR_INVALID_CAST_INTEGRAL_TYPE");
        }
    }

//---------------------------------------------------------------------------------------------
    template<class T> ONLY_FOR_INTEGER  Variant::As()const
    {
        ThrowIfFalse( sizeof(T)>=SizeData() && IsInteger() );
        return CastType<T>();
    }
//---------------------------------------------------------------------------------------------
    template<class T> ONLY_FOR_FLOATING Variant::As()const
    {
        ThrowIfFalse( sizeof(T)>=SizeData() && (IsFloating() || IsInteger()) );
        return CastType<T>();
    }
//---------------------------------------------------------------------------------------------
    template<class T> ONLY_FOR_STRICT&  Variant::As()             { return *this; }
    template<class T> const ONLY_FOR_STRICT&  Variant::As()const  { return *this; }
//---------------------------------------------------------------------------------------------
    template<class T> COMPILE_ERROR_FOR_OTHER  Variant::As()const 
    {
        enum { eCOMPILE_ERROR = variant_detail::PropertyType<T>::eIS_OTHER };
        static_assert( !eCOMPILE_ERROR, "THIS_TYPE_IS_NOT_SUPPORT" );
        return Variant();
    }
//---------------------------------------------------------------------------------------------
    #define RETURN_IF_GRATIFY(type)                     \
        if( ::std::numeric_limits<type>::max()>= v )    \
        return Variant( static_cast<type>(v) ) ;

    template<class T> Variant Variant::Limits(const T& v, ONLY_FOR_SIGNED_INTEGER*)
    {
        RETURN_IF_GRATIFY(I8);
        RETURN_IF_GRATIFY(I16);
        RETURN_IF_GRATIFY(I32);
        RETURN_IF_GRATIFY(I64);
        return Variant(v);
    }
    template<class T> Variant Variant::Limits(const T& v, ONLY_FOR_USIGNED_INTEGER*)
    {
        RETURN_IF_GRATIFY(U8);
        RETURN_IF_GRATIFY(U16);
        RETURN_IF_GRATIFY(U32);
        RETURN_IF_GRATIFY(U64);
        return Variant(v);
    }
    template<class T> Variant Variant::Limits(const T& v, ONLY_FOR_FLOATING*)
    {
        RETURN_IF_GRATIFY(F32);
        RETURN_IF_GRATIFY(F64);
        return Variant(v);
    }
    template<class T> Variant Variant::Limits(const T& v, ONLY_FOR_STRICT*) { return Variant(v); }

    template<class T> Variant Limits(const T& v, COMPILE_ERROR_FOR_OTHER*)
    {
        enum { eCOMPILE_ERROR = variant_detail::PropertyType<T>::eIS_OTHER };
        static_assert( !eCOMPILE_ERROR, "THIS_TYPE_IS_NOT_SUPPORT" );
        return Variant();
    }
//---------------------------------------------------------------------------------------------
    #undef RETURN_IF_GRATIFY
    #undef ONLY_FOR_SIGNED_INTEGER 
    #undef ONLY_FOR_USIGNED_INTEGER 

    #undef ONLY_FOR_INTEGER
    #undef ONLY_FOR_FLOATING 
    #undef ONLY_FOR_STRICT 
    #undef COMPILE_ERROR_FOR_OTHER 
//---------------------------------------------------------------------------------------------
    template<class T> Variant Variant::MakeMinsize(const T& v) { return Limits(v); }
//---------------------------------------------------------------------------------------------

#ifdef VARIANT_SERIALIZATION


    template<int EnumID> struct BFilter
    {
        typedef typename  variant_detail::Enum2Type<EnumID>::Type Type;
        enum { eEXCLUDE = variant_detail::WorkStatus<EnumID>::eSTATUS == variant_detail::DISABLED };
    };
    template<> struct BFilter<variant_detail::eEND_TYPE>
    {
        enum { eEXCLUDE = 1 };
    };

    template<int EnumID = variant_detail::eNULL+1, bool exlcude = BFilter<EnumID>::eEXCLUDE > 
    struct VariantSerialize
    {
        typedef typename variant_detail::Enum2Type<EnumID>::Type Type;

        template<class Archive> static void Serialize(Archive& arch, const Variant& src)
        {
            const auto type = src.GetType();
            if(type==EnumID)
            {
                const Type& t = src.Get<Type>();
                arch << boost::serialization::make_nvp("mType", type);
                arch << boost::serialization::make_nvp("mData", t);
            }
            else
                return VariantSerialize<EnumID+1>::Serialize(arch, src);
        }
        template<class Archive> static void DeSerialize(Archive& arch, Variant& dst)
        {
            variant_detail::eTYPE type = variant_detail::eNULL;
            arch >> boost::serialization::make_nvp("mType", type);

            if(type==variant_detail::eNULL)
                return;

            return VariantSerialize<EnumID>::DeSerialize(arch, dst, type);
        }
        template<class Archive> static void DeSerialize(Archive& arch, Variant& dst, const variant_detail::eTYPE type)
        {
            if(type==EnumID)
            {
                dst = Type();
                Type& t = dst.Get<Type>();
                arch >> boost::serialization::make_nvp("mData",t);
                int a=10;
            }
            else
                return VariantSerialize<EnumID+1>::DeSerialize(arch, dst,type);
        }
    };

    template<> struct VariantSerialize<variant_detail::eEND_TYPE, 1>
    {
        template<class Archive> static void Serialize(Archive&, const Variant&)
        {
            #ifdef DEBUG
            const bool ERROR_INVALID_TYPE = true;
            assert(!ERROR_INVALID_TYPE);
            #endif
        }
        template<class Archive> static void DeSerialize(Archive& , Variant&)
        {
            #ifdef DEBUG
            const bool ERROR_INVALID_TYPE = true;
            assert(!ERROR_INVALID_TYPE);
            #endif
        }
        template<class Archive> static void DeSerialize(Archive& , Variant&, const variant_detail::eTYPE)
        {
            #ifdef DEBUG
            const bool ERROR_INVALID_TYPE = true;
            assert(!ERROR_INVALID_TYPE);
            #endif
        }
    };


    template<class Archive>void Variant::save(Archive& arch, const unsigned int /*version*/) const
    {
        eTYPE type = variant_detail::eNULL;
        if( Empty() )
        {
            arch << boost::serialization::make_nvp("mType", type);
            return;
        }

        VariantSerialize<>::template Serialize(arch, *this);
    }
    template<class Archive>void Variant::load(Archive & arch, const unsigned int /*version*/)
    {
        VariantSerialize<>::DeSerialize(arch, *this);
    }

#endif //VARIANT_SERIALIZATION
    

//---------------------------------------------------------------------------------------------













#if 0
    template<int EnumID> struct BFilter
    {
        typedef typename  variant_detail::Enum2Type<EnumID>::Type Type;
        enum { eEXCLUDE = variant_detail::WorkStatus<EnumID>::eSTATUS == variant_detail::DISABLED };
    };
    template<> struct BFilter<variant_detail::eEND_TYPE>
    {
        enum { eEXCLUDE = 1 };
    };

    template<int EnumID = eNULL+1, 
        bool exlcude = BFilter<EnumID>::eEXCLUDE == DISABLED > 
    struct BuildHelper
    {
        typedef Variant::Helper Helper;
        typedef typename variant_detail::Enum2Type<EnumID>::Type Type;
        static Helper Build(const variant_detail::eTYPE type)
        {
            if(type==EnumID)
                return Helper();
            else
                return BuildHelper<EnumID+1>::Build(type);
        }
    };

    template<> struct BuildHelper<variant_detail::eEND_TYPE, 1>
    {
        //typedef variant_detail::Helper<char> Help;
        typedef Variant::Helper Helper;

        static Helper Build(const variant_detail::eTYPE)
        {
            const bool ERROR_INVALID_TYPE = true;
            assert(!ERROR_INVALID_TYPE);
            return Helper();
        }
    };
#endif


#if 0
    template<class Archive> void Variant::save(Archive& arch, const unsigned int /*version*/) const
    {
        eTYPE type = variant_detail::eNULL;
        if( Empty() )
        {
            arch << boost::serialization::make_nvp("mType", type);
            return;
        }

        mHelper->SetOwner(*this);
        type = mHelper->GetType();
        arch << boost::serialization::make_nvp("mType", type);
        arch << boost::serialization::make_nvp("mData", *mHelper );
    }

//---------------------------------------------------------------------------------------------
    template<class Archive>void Variant::load(Archive& arch, const unsigned int /*version*/)
    {
        (void)arch;
        eTYPE type =eNULL;

        arch >> boost::serialization::make_nvp("mType", type);
        
        if(type==eNULL)
            return;

        mHelper = BuildHelper<eNULL+1>::Build(type);
        arch >> boost::serialization::make_nvp("mData", *mHelper );
    }
#endif
//---------------------------------------------------------------------------------------------


}//namespace tools
